/*
	main source file for the bakery algorithm test (64 bit)
*/

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<stdint.h>

#define THREAD_COUNT 4

extern int BakerySetup(uint32_t thread_count, uint32_t *bk_struct);
extern int BakeryEnter(uint32_t thread_id, uint32_t *bk_struct);
extern int BakeryLeave(uint32_t thread_id, uint32_t *bk_struct);

typedef struct
{
	int TID;
	uint32_t *bk_struct;
	HANDLE thread;
	LPDWORD sys_tid;
} thread_data;

DWORD WINAPI ThreadFunction(LPVOID thread_structure)
{
	thread_data *tdata = (thread_data*)thread_structure;
	int i, t;
	t = 0;

	for(i = 0; i < 5; i++)
	{
		t = BakeryEnter(tdata->TID, tdata->bk_struct);

		printf("\nHELLO I AM THREAD %u ticket: %u", tdata->TID, t);
		printf("\n%u %u: A", tdata->TID, i);
		printf("\n%u %u: B", tdata->TID, i);
		printf("\n%u %u: C", tdata->TID, i);
		printf("\n%u %u: D", tdata->TID, i);
		printf("\n%u %u: E", tdata->TID, i);
		printf("\n%u %u: F", tdata->TID, i);
		printf("\n%u %u: G", tdata->TID, i);

		BakeryLeave(tdata->TID, tdata->bk_struct);
		
	}

	return 0;
}

int main()
{
	// declare stuff
	uint32_t *bk_buffer;
	thread_data tdata[THREAD_COUNT];
	int i;

	// print hello and wait
	printf("Hello World!");

	// allocate buffer for bakery lock (4k) and print the address (for debug purposes)
	bk_buffer = (uint32_t*)malloc(4096);
	BakerySetup(THREAD_COUNT * 2, bk_buffer);
	printf("\nbuffer at :0x%x", (unsigned long long int)bk_buffer);

	
	// create thread data structures
	for(i = 0; i < THREAD_COUNT; i++)
	{
		tdata[i].TID = i;
		tdata[i].bk_struct = bk_buffer;
		tdata[i].thread = CreateThread(NULL, 0, ThreadFunction, (void*)&tdata[i], 0, NULL);

		if(tdata[i].thread == NULL)
		{
			// thread creation failed
			printf("\nThread creation failed TID: %u", tdata[i].TID);
			getchar();
			return 0xdeadbeef;
		}
		
	}
	
	// wait for input
	getchar();
	bk_buffer[512] = 0;

	// start second set of threads going
	for(i = 0; i < THREAD_COUNT; i++)
	{
		tdata[i].TID = i + THREAD_COUNT;
		tdata[i].bk_struct = bk_buffer;
		tdata[i].thread = CreateThread(NULL, 0, ThreadFunction, (void*)&tdata[i], 0, NULL);

		if(tdata[i].thread == NULL)
		{
			// thread creation failed
			printf("\nThread creation failed TID: %u", tdata[i].TID);
			getchar();
			return 0xdeadbeef;
		}
		
	}

	// get input and finish
	getchar();
	return 0;
}